﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GoodStuff.Text
{
    /// <summary>
    /// Utility class to splits comma separated strings into multiple columns. Used by the CSVStreamReader
    /// </summary>
    public class CSVStringSplitter
    {
        private const char QUOTE = '\"';

        /// <summary>
        /// Constructs a new stringsplitter with a specified sepator
        /// </summary>
        /// <param name="separator">The separator to use.</param>
        public CSVStringSplitter(string separator)
        {
            Separator = separator;
        }

        /// <summary>
        /// Returns the separator for the current splitter.
        /// </summary>
        public string Separator { get; private set; }

        /// <summary>
        /// Splits an input string into multiple columns. 
        /// </summary>
        /// <param name="input"></param>
        /// <returns>an array of string values.</returns>
        /// <remarks>any strings containing the separator should be properly escaped by quotes.
        /// Any inside quote should be escaped by double quotes.</remarks>
        public string[] Split(string input)
        {
            //next element at comma, escaped by ", " escaped by ""
            int pos = 0;
            List<string> results = new List<string>();
            StringBuilder sb = new StringBuilder();
            bool inQuote = false;

            while (pos < input.Length)
            {
                if (!inQuote)
                {
                    //begins with separator
                    if (string.Compare(input, pos, Separator, 0, Separator.Length) == 0)
                    {
                        //eat separator.
                        pos += Separator.Length;

                        //append the buffer.
                        results.Add(sb.ToString().Trim());
                        sb = new StringBuilder();
                    }
                    else
                    {
                        if (input[pos] == QUOTE)
                        {
                            inQuote = true;
                            pos++;
                        }
                        else
                        {
                            //eat character
                            sb.Append(input[pos]);
                            pos++;
                        }
                    }
                }
                else
                {
                    if (string.Compare(input, pos, "\"\"", 0, 2) == 0)
                    {
                        //eat separator.
                        sb.Append(QUOTE);
                        pos += 2;
                    }
                    else
                    {
                        if (input[pos] == QUOTE)
                        {
                            inQuote = false;
                            pos++;
                        }
                        else
                        {
                            sb.Append(input[pos]);
                            pos++;
                        }
                    }
                }                
            }

            //add the remainder.
            if (pos > 0 || sb.Length > 0)
            {
                results.Add(sb.ToString().Trim());  
            }

            if (inQuote)
            {
                throw new FormatException("Missing closing quote.");
            }

            return results.ToArray();
        }
    }
}
